package com.ktjiaoyu.server.service.impl;

import com.ktjiaoyu.server.pojo.Admin;
import com.ktjiaoyu.server.pojo.Leavebill;
import com.ktjiaoyu.server.pojo.RespBean;
import com.ktjiaoyu.server.service.ILeavebillService;
import com.ktjiaoyu.server.service.IWorkFlowService;
import com.ktjiaoyu.server.utils.SysConstants;
import com.ktjiaoyu.server.vo.*;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.zip.ZipInputStream;

@Service
public class WorkFlowServiceImpl implements IWorkFlowService {
    @Resource
    RepositoryService repositoryService;
    @Resource
    RuntimeService runtimeService;
    @Resource
    ILeavebillService leavebillService;
    @Resource
    TaskService taskService;
    @Resource
    HistoryService historyService;

    @Override
    public RespBean queryProcessDeploy(WorkFlowVo workFlowVo) {
        String name=workFlowVo.getDeploymentName();
        if(name==null){
            name="";
        }
        //获取总记录数
        long count = repositoryService.createDeploymentQuery()
                .deploymentNameLike("%" + name + "%").count();
        //获取每页显示的数据
        Integer pageBegin=(workFlowVo.getCurrPageNo()-1)*workFlowVo.getPageSize();
        Integer pageSize=workFlowVo.getPageSize();
        List<Deployment> list = repositoryService.createDeploymentQuery()
                .deploymentNameLike("%" + name + "%").listPage(pageBegin, pageSize);

        List<ActDeploymentEntity> data=new ArrayList<>();
        for (Deployment deployment : list) {
            ActDeploymentEntity entity=new ActDeploymentEntity();
            BeanUtils.copyProperties(deployment,entity);
            data.add(entity);
        }

        Map<String,Object> map=new HashMap<>();
        map.put("list",data);
        map.put("totalCount",count);

        return new RespBean(200,"查询部署记录成功",map);
    }

    @Override
    public RespBean loadAllProcessDefinition(WorkFlowVo workFlowVo) {
        String name=workFlowVo.getDeploymentName();
        if(name==null){
            name="";
        }
        //查询所有的流程部署记录
        List<Deployment> list = repositoryService.createDeploymentQuery()
                .deploymentNameLike("%" + name + "%").list();
        Set<String> deploymentIds=new HashSet<>();
        for (Deployment deployment : list) {
            deploymentIds.add(deployment.getId());
        }

        //查询总记录数
        long count = repositoryService.createProcessDefinitionQuery()
                .deploymentIds(deploymentIds).count();
        //每页显示的数据
        Integer pageBegin=(workFlowVo.getCurrPageNo()-1)*workFlowVo.getPageSize();
        Integer pageSize=workFlowVo.getPageSize();
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                .deploymentIds(deploymentIds).listPage(pageBegin, pageSize);
        List<ActProcessDefinitionEntity> data=new ArrayList<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            ActProcessDefinitionEntity entity=new ActProcessDefinitionEntity();
            BeanUtils.copyProperties(processDefinition,entity);
            data.add(entity);
        }

        Map<String,Object> map=new HashMap<>();
        map.put("list",data);
        map.put("totalCount",count);

        return new RespBean(200,"查询流程定义成功",map);
    }

    @Override
    public void addWorkFlow(InputStream inputStream, String deploymentName) {
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        try {
            // 调用deploy()方法完成流程部署
            Deployment deploy = repositoryService
                    .createDeployment()
                    .name(deploymentName)
                    .addZipInputStream(zipInputStream)
                    .deploy();
            System.out.println("请求流程部署成功，流程部署ID： " + deploy.getId());
            zipInputStream.close();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public InputStream queryProcessDeploymentImage(String deploymentId) {
        //1.获取流程定义对象
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();
        //2.获取流程模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());

        //3.使用ProcessDiagramGenerator生成png图片
        ProcessDiagramGenerator pd=new DefaultProcessDiagramGenerator();
        InputStream inputStream = pd
                .generateDiagram(bpmnModel, "png", "宋体", "宋体", null);

        return inputStream;
    }

    @Override
    public void startProcess(Integer id) {
        Admin admin=(Admin)SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();

        //1.启动
        String key="LeaveBill";
        Map<String, Object> map = new HashMap<String,Object>();
        map.put("username",admin.getName()); //任务处理人为当前登录用户
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey(key,id+"",map);

        //2.完成提交任务
//        Task task = taskService.createTaskQuery()
//                .processInstanceId(processInstance.getId())
//                .singleResult();
//        taskService.complete(task.getId());

        //3.修改请假单状态
        Leavebill leavebill = leavebillService.getById(id);
        leavebill.setState(SysConstants.STATE_LEAVEBILL_ONE);
        leavebillService.updateById(leavebill);
    }

    @Override
    public RespBean queryCurrentUserTask(WorkFlowVo workFlowVo) {
        Admin admin=(Admin)SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();

        //获取查询对象
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskAssignee(admin.getName());
        //拼接条件
        if(workFlowVo.getBeginTime()!=null&&workFlowVo.getEndTime()!=null){
            taskQuery.taskCreatedBefore(workFlowVo.getEndTime())
                    .taskCreatedAfter(workFlowVo.getBeginTime());
        }

        //分页查询
        //查询总数
        long count = taskQuery.count();
        //查询分页数据
        Integer pageBegin=(workFlowVo.getCurrPageNo()-1)*workFlowVo.getPageSize();
        Integer pageSize=workFlowVo.getPageSize();
        List<Task> list = taskQuery.listPage(pageBegin, pageSize);

        List<ActTaskEntity> data=new ArrayList<>();
        for (Task task : list) {
            ActTaskEntity actTaskEntity=new ActTaskEntity();
            BeanUtils.copyProperties(task,actTaskEntity);
            data.add(actTaskEntity);
        }

        Map<String,Object> map=new HashMap<>();
        map.put("list",data);
        map.put("totalCount",count);

        return RespBean.success("查询我的待办任务成功",map);
    }

    @Override
    public void deleteWorkFlow(String deploymentId) {
        // 参数为true表示级联删除，即先删除流程定义表再删除流程部署表中的信息
        this.repositoryService.deleteDeployment(deploymentId, true);
    }

    @Override
    public RespBean queryLeaveBillByTaskId(String taskId) {
        //1.根据任务id查询流程实例id
        Task task = taskService.createTaskQuery()
                .taskId(taskId).singleResult();
        String processInstanceId=task.getProcessInstanceId();
        //2.根据流程实例id查询businessKey
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        String businessKey=processInstance.getBusinessKey();
        //3.根据businessKey查询请假单数据
        Leavebill leavebill = leavebillService.getById(businessKey);
        return RespBean.success("查询请假单数据成功",leavebill);
    }

    @Override
    public RespBean queryOutcomeByTaskId(String taskId) {
        //1.根据任务id查询当前执行任务的id
        Task task = taskService.createTaskQuery()
                .taskId(taskId).singleResult();
        String executionId=task.getExecutionId();
        //2.根据流程实例id查询actid
        Execution execution = runtimeService.createExecutionQuery()
                .executionId(executionId).singleResult();
        String actId=execution.getActivityId();
        //3.获取当前正在执行的任务节点对象
        BpmnModel bpmnModel = repositoryService
                .getBpmnModel(task.getProcessDefinitionId());
        //3.1获取点一个节点
        Process process = bpmnModel.getProcesses().get(0);
        //3.2 获取第一个节点下面所有的用户任务节点
        List<UserTask> list = process.findFlowElementsOfType(UserTask.class);

        UserTask currentUserTask=null;
        for (UserTask userTask : list) {
            if(userTask.getId().equals(actId)){
                currentUserTask=userTask;
                break;
            }
        }
        //4.找当前执行任务节点下面的连线
        List<SequenceFlow> outgoingFlows = currentUserTask.getOutgoingFlows();
        List<String> names=new ArrayList<>();
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            names.add(outgoingFlow.getName());
        }
        return RespBean.success("根据任务id查询当前任务节点下面的连线成功",names);
    }

    @Override
    public RespBean queryCommentByTaskId(String taskId) {
        //1.根据任务id查询流程实例id
        Task task = taskService.createTaskQuery()
                .taskId(taskId).singleResult();
        String processInstanceId=task.getProcessInstanceId();
        //2.根据流程实例id查询批注
        List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId);
        List<ActCommentEntity> data=new ArrayList<>();
        for (Comment comment : comments) {
            ActCommentEntity entity=new ActCommentEntity();
            BeanUtils.copyProperties(comment,entity);
            data.add(entity);
        }
        return RespBean.success("查询批注成功",data);
    }

    @Override
    public void completeTask(WorkFlowVo workFlowVo) {
        //1.插入批注信息
        //1.1根据任务id查询流程实例id
        Task task = taskService.createTaskQuery()
                .taskId(workFlowVo.getTaskId()).singleResult();
        String processInstanceId=task.getProcessInstanceId();
        //1.2 设置批注人
        Admin admin = ((Admin) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal());
        Authentication.setAuthenticatedUserId(admin.getName());
        //1.3 设置批注内容
        taskService.addComment(workFlowVo.getTaskId(),processInstanceId,
                "["+workFlowVo.getOutcome()+"]"+workFlowVo.getComment());
        //2.完成任务
        Map<String,Object> map=new HashMap<>();
        map.put("outcome",workFlowVo.getOutcome());
        taskService.complete(workFlowVo.getTaskId(),map);
        //3.修改请假单状态
        //3.1.根据流程实例id查询流程对象
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        if(processInstance==null){
            Leavebill leavebill = leavebillService.getById(workFlowVo.getId());
            if(workFlowVo.getOutcome().equals("放弃")){
                leavebill.setState(SysConstants.STATE_LEAVEBILL_THREE);
            }else{
                leavebill.setState(SysConstants.STATE_LEAVEBILL_TWO);
            }
            leavebillService.updateById(leavebill);
        }
    }
}
